package com.bungarus.sdk.handler;

import com.bungarus.codec.protobuf.MessageProtobuf;
import com.bungarus.sdk.*;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import org.apache.log4j.Logger;

import java.net.InetSocketAddress;
import java.net.SocketAddress;

/**
 * Created by tang on 2019/1/29.
 */
@ChannelHandler.Sharable
public class ClientHandler extends ChannelInboundHandlerAdapter {
    private static Logger logger = Logger.getLogger(ClientHandler.class);

    final private Callback<EndUser, Void> callback;
    public ClientHandler(Callback<EndUser, Void> callback) {
        this.callback = callback;
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        MessageProtobuf.Message message = (MessageProtobuf.Message)msg;
        MessageProtobuf.Header header = message.getHeader();
        if(null != header){
            int type = header.getType();
            switch (type){
                case MessageType.AUTH:
                    if(MessageStatus.OK == header.getReturnCode()) {
                        callback.call(new EndUser(header.getFrom(),
                                header.getTenantID(),
                                header.getSessionId(),
                                header.getToken(),
                                header.getKey()));
                    }
                    break;
                case MessageType.LOGOUT:
                    callback.call(new EndUser(header.getFrom(),
                            header.getTenantID(),
                            "",
                            "",
                            ""));
                    break;
                default:
                    ((Client)callback).doBusiness(message);
                    break;
            }
        }
        ctx.writeAndFlush(MessageBuilder.buildAckMessage(message.getHeader().getId()));
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        SocketAddress sa = ctx.channel().remoteAddress();
        logger.debug("Connection broken, begin to reconnect to => " + sa.toString());
        reconnect((InetSocketAddress)sa);
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        logger.error("Connection terminated !");
        ctx.close();
    }

    private void reconnect(InetSocketAddress socketAddress) {
        MessageProtobuf.Header header = MessageProtobuf.Header.newBuilder()
                .setType(MessageType.ENDUSER_RECONNECT)
                .setTo(socketAddress.getHostString() + ":" + socketAddress.getPort())
                .build();
        MessageProtobuf.Message message = MessageProtobuf.Message.newBuilder()
                .setHeader(header)
                .build();

        Client client = (Client)callback;
        client.setChannel(null);
        client.doBusiness(message);
    }
}

